/*
 * Два коня
 */

#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef DEBUG
# define debug_fprintf(x)	fprintf x
#else
# define debug_fprintf(x)	((void) 0)
#endif

#define S_assert(st) ((st)?((void)0):(void)fprintf(stderr,"Assertion (soft) \"%s\" in %s:%s():%d: failed.\n",#st,__FILE__,__func__,__LINE__))

#define MEMDEBUG 1

/* queue */
struct queue {
	char *data;
	size_t _data_size;

	int head;
	int n;
	int _max;
};

/* stack */
struct stack {
	char *data;
	size_t n; /* how many elements in the stack atm */
	size_t _data_size; /* size of one element (in bytes) */
	size_t _allocated; /* how much storage is allocated for *data (in bytes) */
	size_t _max; /* maximum storage that we are allowed allocate for *data */
};

/* autoarray */
struct vector {
	char *data;
	size_t _elem_size;

	int n;
	int _max;
};

/* doubly-linked list */
struct dll_node {
	int x, y;
	char *data;
	size_t _data_size;
	struct dll_node *prev, *next;
};

/* priority queue */
struct pqueue {
	char *data; /* threres a reason why i use a continuous array */
	size_t _data_size;

	int n; /* amount of elements in the queue */
	int _max; /* maximum space allocated for .data */
	int (*cmp)(const void *, const void *); /* comaparator function */

	bool _autoexpand; /* trigger autoexpansion on new element insertion */
};

struct bpos {
	int8_t x, y;
};

#define White ((int8_t)1)
#define Black ((int8_t)2)
#define START ((int8_t)4)

struct tilestate {
	struct bpos wht, blk;
	int prev;
	int8_t w;
};

int d[][2] = {
	{ -2,  1 },
	{ -1,  2 },
	{  1,  2 },
	{  2,  1 },
	{  2, -1 },
	{  1, -2 },
	{ -1, -2 },
	{ -2, -1 },
};

/* {{{ function prototypes */
/* memory allocation wrappers */
void *s_calloc(size_t n, size_t size);
void *s_malloc(size_t size);
void *s_realloc(void *oldptr, size_t newsize);

struct queue *queue__new(const int n, const size_t elem_size);
int queue__push(struct queue *q, const void *p);
int queue__pop(struct queue *q, void *buf);
int queue__cleanup(struct queue *q);

/*
 * int vector_init(struct vector *v, int p);
 * int vector_append(struct vector *v, int a);
 * int vector_sort(struct vector *v, int (*cmpf)(const void *, const void *));
 * int vector_cleanup(struct vector *v);
 */

struct vector *vector__new(size_t elem_size, int p);
int vector__append(struct vector *v, const void *app);
char *vector__get_by_idx(struct vector *v, const int idx);
int vector__cleanup(struct vector *v);

struct dll_node *dll_insert(struct dll_node *node, struct dll_node *ins);
struct dll_node *dll_delete(struct dll_node *node);
void dll_mergesort(struct dll_node *head, int (*cmp)(const void *, const void *));

/* mergesort (with copy array optimization) */
void mergesort(void *base, size_t nmemb, size_t size,
		int (*cmpf)(const void *, const void *));

struct pqueue *pqueue__new(const size_t elem_size, int exp,
		const bool autoexpand, int (*f)(const void *, const void *));
int pqueue__insert(struct pqueue *pq, const void *elem);
int pqueue__extract(struct pqueue *pq, void *buf);
int pqueue__cleanup(struct pqueue *pq);

void adjl_dll_connect(struct adjlist_dll *, const int, const int);
void adjl_dll_cleanup(struct adjlist_dll *al);

/* misc */
struct dll_node *vector_to_dll_list(struct vector *v);
char *bytes_to_str(const void *ptr, const size_t size);

/* KMP */

/* }}} */

/* {{{ memory allocation wrappers */
extern void *s_calloc(size_t n, size_t size)
{
	void *ptr;
	ptr = calloc(n, size);
	assert(ptr != NULL);
	if (ptr == NULL) {
		fprintf(stderr, "%s(): out of memory, failed to allocate %lu bytes\n",
				__func__, n * size);
		abort();
	}
	return ptr;
}

extern void *s_malloc(size_t size)
{
	void *ptr;
	ptr = malloc(size);
	assert(ptr != NULL);
	if (ptr == NULL) {
		fprintf(stderr, "%s(): out of memory, failed to allocate %lu bytes\n",
				__func__, size);
		abort();
	}
	return ptr;
}

extern void *s_realloc(void *oldptr, size_t newsize)
{
	void *newptr;
#ifdef MEMDEBUG
	fprintf(stderr, "%s(): realloc oldptr %p for new size %lu (%.3f MiB)\n", __func__, oldptr, newsize, (float) newsize / (1024.0f * 1024.0f));
#endif
	newptr = realloc(oldptr, newsize);
	if (newptr == NULL) {
		fprintf(stderr, "%s(): out of memory, "
				"failed to realloc %p for new size of %lu bytes\n",
				__func__, oldptr, newsize);
		abort();
	}
#ifdef MEMDEBUG
	fprintf(stderr, "%s(): newptr %p\n", __func__, newptr);
#endif /* MEMDEBUG */
	return newptr;
}
/* }}} */

/* {{{ queue */
extern struct queue *
queue__new(const int n, const size_t elem_size)
{
	struct queue *q = NULL;

	assert(n > 1);
	assert(elem_size > 0);

	q = (struct queue *) s_malloc(sizeof *q);
	q->data = (char *) s_calloc(n, elem_size);
	q->_data_size = elem_size;
	q->head = 0;
	q->n = 0;
	q->_max = n;

	return q;
}

extern int
queue__push(struct queue *q, const void *p)
{
	assert(q != NULL);
	assert(p != NULL);

	if (q->n >= q->_max) {
		debug_fprintf((stderr, "%s(): q->n (%d) >= q->_max (%d), can't push any deeper :-(\n",
				__func__, q->n, q->_max));
		return -1; /* can't push any further */
	}

	memcpy(q->data + ((q->head + q->n++) % q->_max) * q->_data_size, p, q->_data_size);
	debug_fprintf((stderr, "%s(): q->head=%d, q->n=%d\n",
			__func__, q->head, q->n));

	return 0;
}

extern int
queue__pop(struct queue *q, void *buf)
{
	assert(q != NULL);
	assert(buf != NULL);

	memcpy(buf, q->data + (q->head) * q->_data_size, q->_data_size);
	q->head = (q->head + 1) % q->_max;
	q->n--;
	debug_fprintf((stderr, "%s(): q->head=%d, q->n=%d\n",
			__func__, q->head, q->n));

	return 0;
}

extern int
queue__cleanup(struct queue *q)
{
	S_assert(q != NULL);
	if (q == NULL)
		return -1;

	if (q->_max == 0 || q->data == NULL)
		return 1;

	free(q->data);
	q->data = NULL;
	free(q);

	return 0;
}
/* }}} */

/* {{{ autoarray */
extern struct vector *
vector__new(size_t elem_size, int p)
{
	struct vector *v = NULL;

	if (p < 0 || p >= (int) (CHAR_BIT * sizeof v->data[0]))
		p = 0;

	v = (struct vector *) s_malloc(sizeof *v);
	v->_max = 1 << p;
	v->_elem_size = elem_size;
	v->n = 0;
	v->data = (char *) s_calloc((size_t) v->_max, v->_elem_size);

	return v;
}

extern int
vector__append(struct vector *v, const void *app)
{
	int ret = 0;

	if (v == NULL) {
		fprintf(stderr, "%s(): received NULL ptr, not doing anything (-1)\n",
				__func__);
		return -1;
	}

	if (v->_max == 0) {
		/* weird input, fix it */
		ret |= 2;
		debug_fprintf((stderr, "%s(): v->_max is 0, which means that your "
					"autoarray (v=%p) is messed up. trying to fix this.\n",
					__func__, (void*) v));
		if (v->_elem_size == 0) {
			ret |= 4;
			fprintf(stderr, "%s(): can't fix this mess, bailing out (%d)\n",
					__func__, ret);
			return ret;
		} else {
			v->_max = 1;
			v->n = 0;
			v->data = (char *) s_calloc((size_t) v->_max, v->_elem_size);
		}
	}

	if (v->n + 1 >= v->_max) {
		v->data = (char *) s_realloc(v->data, v->_elem_size * (v->_max *= 2));
	}
	memcpy(v->data + (v->n++) * v->_elem_size, app, v->_elem_size);

	return ret;
}

extern char *
vector__get_by_idx(struct vector *v, const int idx)
{
	if (v == NULL) {
		fprintf(stderr, "%s(): received NULL ptr, not doing anything (NULL)\n",
				__func__);
		return NULL;
	}

	if (v->_elem_size == 0) {
		fprintf(stderr, "%s(): whoah, looks like your vector is messed up big time (NULL)\n",
				__func__);
		return NULL;
	}

	if (idx < 0 || idx >= v->n) {
		fprintf(stderr, "%s(): index out of range %d (v->n=%d)\n",
				__func__, idx, v->n);
		return NULL;
	}

	return v->data + (idx) * v->_elem_size;
}

extern int
vector__cleanup(struct vector *v)
{
	int ret = 0;

	if (v == NULL) {
		fprintf(stderr, "%s(): received NULL ptr, not doing anything (-1)\n",
				__func__);
		return -1;
	}

	if (v->_max > 0) {
		v->_max = v->n = 0;
		free(v->data);
		v->data = NULL;
	} else {
		ret |= 1;
	}

	/* TODO: improve logic */
	debug_fprintf((stderr, "%s(): freeing v=%p\n", __func__, (void*) v));
	free(v);

	return ret;
}
/* }}} */

/* {{{ doubly-linked list */
/*
 * This function inserts one node pointed to by 'ins' _after_ 'node'.
 */
extern struct dll_node *
dll_insert(struct dll_node *node, struct dll_node *ins)
{
	assert(node != NULL);
	if (ins == NULL) {
		debug_fprintf((stderr, "dll_insert(): ins is NULL, not doing anything\n"));
		return node;
	}

	if (node->next) {
		assert(node->next->prev == node);
		node->next->prev = ins;
	}
	ins->next = node->next;
	ins->prev = node;
	node->next = ins;
	return ins;
}

/*
 * This function extracts 'node' from a doubly-linked list and returns pointer
 * to that node, pointers '->prev' and '->next' are not reset.
 *
 * If you really want to get rid of a node, call
 * 	free(dll_delete(unneeded_node));
 */
extern struct dll_node *
dll_delete(struct dll_node *node)
{
	if (!node) {
		debug_fprintf((stderr, "dll_delete(): received NULL ptr, wtf am i supposed to delete?\n"));
		return NULL;
	}

	if (node->prev) {
		assert(node->prev->next == node);
		node->prev->next = node->next;
	}
	if (node->next) {
		assert(node->next->prev == node);
		node->next->prev = node->prev;
	}

	return node;
}

/*
 * Merge-sort for doubly-linked list.
 *
 * TODO: work out the use of (*cmp)() function
 */
extern void
dll_mergesort(struct dll_node *head, int (*cmp)(const void *, const void *))
{
	struct dll_node *end, *mid;
	struct dll_node *sorted, *first, *second;
	struct dll_node *swap;

	if (head == NULL || head->next == NULL) /* lengths 0, 1 */
		return;

	end = mid = head;
	while (end && end->next && end->next->next) {
		end = end->next->next;
		mid = mid->next;
	}
	if (end && end->next) {
		end = end->next;
		mid = mid->next;
	}

	mid->prev->next = NULL;
	mid->prev = NULL;
	dll_mergesort(head, cmp);
	dll_mergesort(mid, cmp);

	if (cmp(head->data, mid->data) > 0) { /* this is the tricky part */
		char *t1;
		size_t t2;
		struct dll_node *t3;
		int t4;
#define SWAP_(a,b,t) do{(t)=(a),(a)=(b),(b)=(t);}while(0)
		if (head->next && mid->next)
			SWAP_(head->next->prev, mid->next->prev, t3);
		SWAP_(head->x, mid->x, t4);
		SWAP_(head->data, mid->data, t1);
		SWAP_(head->_data_size, mid->_data_size, t2);
		SWAP_(head->prev, mid->prev, t3);
		SWAP_(head->next, mid->next, t3);
#undef SWAP_
	}

	/*
	 * from now on using only ->prev and ->next pointers should suffice us
	 */
	first = head->next;
	if (first) first->prev = NULL;
	second = mid;

	sorted = head;
	sorted->next = NULL;
	assert(sorted->prev == NULL);

	while (first && second) {
		assert(sorted->next == NULL);

		/* TODO: un-copypaste this code (use 'swap' ptr) */
		if (cmp(first->data, second->data) < 0)
			swap = first;
		else
			swap = second;

		assert(swap->prev == NULL);

		sorted->next = swap;
		swap->prev = sorted;
		sorted = swap;

		swap = swap->next;
		if (swap) {
			assert(swap->prev == sorted);
			swap->prev->next = NULL;
			swap->prev = NULL;
		}
	}
	assert(sorted->next == NULL);
	if (first) {
		assert(first->prev == NULL);
		sorted->next = first;
		first->prev = sorted;
	}
	if (second) {
		assert(second->prev == NULL);
		sorted->next = second;
		second->prev = sorted;
	}
}
/* }}} */

void
evil(struct vector *v, const int cur)
{
	if (cur != -1)
	{
		struct tilestate *S = (struct tilestate *) vector__get_by_idx(v, cur);
		evil(v, S->prev);
		switch (S->w)
		{
			case Black:
				printf("B %c%c\n", S->blk.x + 'a', S->blk.y + '1');
				break;
			case White:
				printf("W %c%c\n", S->wht.x + 'a', S->wht.y + '1');
				break;
			case START:
#ifdef DEBUG
				fprintf(stderr, "reached starting point\n");
#endif /* DEBUG */
				break;
		}
	}
}

void
print_path(struct vector *v, const int last)
{
	int len = 0;
	register int idx;

	idx = last;
	while (idx != 0)
	{
		len++;
		idx = ((struct tilestate *) vector__get_by_idx(v, idx))->prev;
	}
	printf("%d\n", len);
	evil(v, last);
}

int
queen(const char *s1, const char *f1, const char *s2, const char *f2)
{
	struct vector *q;
	struct tilestate T, finish, nxt;
	register long long i = 0;
	static bool visited[8][8][8][8]; //XXX

#define VALID_MOVE(t, i) (t.x + i[0] < 8 && t.y + i[1] < 8 &&\
		          t.x + i[0] >= 0 && t.y + i[1] >= 0)

	q = vector__new(sizeof (struct tilestate), 6);

	T.wht.x = s1[0] - 'a';
	T.wht.y = s1[1] - '1';
	T.blk.x = s2[0] - 'a';
	T.blk.y = s2[1] - '1';
	T.prev = -1;
	T.w = START;
	vector__append(q, &T);
	visited[T.wht.x][T.wht.y][T.blk.x][T.blk.y] = true;

	finish.wht.x = f1[0] - 'a';
	finish.wht.y = f1[1] - '1';
	finish.blk.x = f2[0] - 'a';
	finish.blk.y = f2[1] - '1';

	i = 0;
	while (T.wht.x != finish.wht.x ||
	       T.wht.y != finish.wht.y ||
	       T.blk.x != finish.blk.x ||
	       T.blk.y != finish.blk.y)
	{
		debug_fprintf((stdout, "i=%4lld: W %c%c, B %c%c, prev=%4d\n",
				i, 'A' + T.wht.x, '1' + T.wht.y,
				'A' + T.blk.x, '1' + T.blk.y, T.prev));
		nxt.prev = i;

		if (!(T.wht.x == finish.wht.x && T.wht.y == finish.wht.y))
		{
			nxt.blk = T.blk;
			nxt.w = White;
			for (int dwht = 0; dwht < sizeof d / sizeof d[0]; ++dwht)
			{
				if (VALID_MOVE(T.wht, d[dwht]) &&
				    !(T.wht.x + d[dwht][0] == T.blk.x &&
				      T.wht.y + d[dwht][1] == T.blk.y) &&
					!visited[T.wht.x+d[dwht][0]][T.wht.y+d[dwht][1]][T.blk.x][T.blk.y]) //this should be considered a deadly sin
				{
					nxt.wht.x = T.wht.x + d[dwht][0];
					nxt.wht.y = T.wht.y + d[dwht][1];
					vector__append(q, &nxt);
					visited[nxt.wht.x][nxt.wht.y][nxt.blk.x][nxt.blk.y] = true;
				}
			}
		}

		if (T.blk.x != finish.blk.x || T.blk.y != finish.blk.y)
		{
			nxt.wht = T.wht;
			nxt.w = Black;
			for (int dblk = 0; dblk < sizeof d / sizeof d[0]; ++dblk)
			{
				if (VALID_MOVE(T.blk, d[dblk]) &&
				    !(T.blk.x + d[dblk][0] == T.wht.x &&
				      T.blk.y + d[dblk][1] == T.wht.y) &&
					!visited[T.wht.x][T.wht.y][T.blk.x+d[dblk][0]][T.blk.y+d[dblk][1]])
				{
					nxt.blk.x = T.blk.x + d[dblk][0];
					nxt.blk.y = T.blk.y + d[dblk][1];
					vector__append(q, &nxt);
					visited[nxt.wht.x][nxt.wht.y][nxt.blk.x][nxt.blk.y] = true;
				}
			}
		}

		T = * (struct tilestate *) vector__get_by_idx(q, ++i);
		// if (i > 1 << 24)
		// {
		//         fprintf(stderr, "too many iterations\n");
		//         break;
		// }
	}

	fprintf(stderr, "%lld iterations\n", i);

	debug_fprintf((stdout, "i=%4lld: W %c%c, B %c%c, prev=%4d !\n",
			i, 'A' + T.wht.x, '1' + T.wht.y,
			'A' + T.blk.x, '1' + T.blk.y, T.prev));
	if (T.wht.x == finish.wht.x && T.wht.y == finish.wht.y &&
	    T.blk.x == finish.blk.x && T.blk.y == finish.blk.y)
		print_path(q, i);

	vector__cleanup(q);

#undef VALID_MOVE
	return 0;
}

int
main(int argc, char **argv)
{
	char s1c[3], f1c[3], s2c[3], f2c[3];
	scanf("%2s %2s %2s %2s", s1c, s2c, f1c, f2c);
	queen(s1c, f1c, s2c, f2c);
	return 0;
}
